home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.06 Jun 89 / Pict2Rgn Source / MakeRgn.a next >
Encoding:
Text File  |  1988-04-10  |  9.1 KB  |  268 lines  |  [TEXT/MPS ]

  1. ;-------------------------------------------------------------------------
  2. ;
  3. ; MakeRgn.a
  4. ;
  5. ; Written by Ted Cohn, March 1987.
  6. ; Copyright 1988 By Ted Cohn.
  7. ;
  8. ; The function MakeRgn converts a bitmap image into a Quickdraw region.
  9. ; The image bits which are 1 are logically included in the resultant
  10. ; region whereas 0 bits are not included.  There are no special
  11. ; conditions required of the bitmap - it may be arbitrarily complex.
  12. ; An empty bitmap will simply yield an empty region.  The rgnBBox of
  13. ; the resultant region may be smaller than the initial bitmap bounds
  14. ; if the image does not use the full extent of the bitmap.  The rgnBBox
  15. ; will be the smallest rectangle enclosing the resultant region.
  16. ;
  17. ; Algorithm Summary:
  18. ;
  19. ; The idea behind the conversion is simple.  The key is in finding
  20. ; the inversion points of the picture which define the region.
  21. ; A source bitmap is first XOR'd with its right-shifted copy.  The resultant
  22. ; bitmap is then XOR'd with its down-shifted copy.  This produces a set of
  23. ; inversion points which define the region boundary.  The next step is to take
  24. ; these points within the final bitmap and convert them to Quickdraw region
  25. ; format.
  26. ;
  27. ; FUNCTION MakeRgn(image: BitMap): RgnHandle;
  28. ;
  29. ; Modification History:
  30. ;
  31. ; 25-Mar-87  New Today.
  32. ; 26-Mar-87  Ironed out bugs.
  33. ; 30-Mar-87  Changed to Pascal function.
  34. ; 28-Mar-88  Optimized and reduced code.
  35. ;-------------------------------------------------------------------------
  36.  
  37.         MACHINE    MC68000
  38.         
  39.         INCLUDE 'Traps.a'
  40.         INCLUDE 'QuickEqu.a'
  41.  
  42. ENDMARK        EQU    $7FFF            ; endmark [word].
  43.  
  44. ; MakeRgn's stack frame:
  45.  
  46. MRFrame        RECORD    {A6Link},DECREMENT
  47. dstRgn        DS.L    1            ; output region [RgnHandle].
  48. srcMap        DS.L    1            ; source bitmap [Ptr].
  49. Return        DS.L    1            ; return address [Ptr].
  50. A6Link        DS.L    1            ; old A6 value [long].
  51. srcRect        DS.B    8            ; temp [Rect].
  52. dstRect        DS.B    8            ; temp [Rect].
  53. rgnMap        DS.B    14            ; temp bitmap [BitMap].
  54. VarSize        EQU    *            ; size of local variables.
  55.         ENDR
  56.  
  57. MakeRgn        PROC    EXPORT
  58.         WITH    MRFrame
  59.         LINK    A6,#VarSize        ; create local stack frame.
  60.         MOVEM.L    A1-A3/D0-D7,-(SP)    ; save working registers.
  61.         MOVE.L    srcMap(A6),A3        ; load ptr to source bitmap.
  62.         MOVEQ    #0,D0            ; clear for multiplying.
  63.         MOVEQ    #0,D4            ; use D4 for faster clears.
  64.         MOVE.W    rowBytes(A3),D7        ; load srcMap rowBytes.
  65. ;
  66. ; Find number of lines in the source bitmap.  The rgnMap will have
  67. ; the same number of lines plus one and two more rowbytes.
  68. ;
  69.         MOVE.W    bounds+bottom(A3),D0    ; load srcMap bottom.
  70.         SUB.W    bounds+top(A3),D0    ; height = bottom-top.
  71.         ADDQ.W    #1,D0            ; height++.
  72.         ADDQ.W    #2,D7            ; rowBytes += 2.
  73. ;
  74. ; Fill in rgnMap rowBytes and baseAddr fields.  Allocate memory
  75. ; for the temporary rgnMap image buffer.
  76. ;
  77.         MOVE.W    D7,rgnMap+rowBytes(A6)    ; store new rowBytes.
  78.         MULU    D7,D0            ; calculate bitmap size.
  79.         _NewPtr    ,clear            ; create rgnMap image buffer.
  80.         MOVE.L    A0,rgnMap+baseAddr(A6)    ; store start of buffer.
  81. ;
  82. ; The rgnMap's bounds will be one pixel larger to the right and bottom.
  83. ;
  84.         MOVE.L    bounds+topLeft(A3),D0    ; get original bitmap bounds.
  85.         MOVE.L    bounds+botRight(A3),D1
  86.         ADDQ.W    #1,D1            ; right++.
  87.         MOVE.L    D0,rgnMap+bounds+topLeft(A6)
  88.         MOVE.L    D1,rgnMap+bounds+botRight(A6)
  89.         ADDQ.W    #1,rgnMap+bounds+bottom(A6)
  90. ;
  91. ; Now make right-shifted copy in rgnMap.
  92. ;
  93.         ADDQ.W    #1,D0            ; left++.
  94.         MOVE.L    D0,dstRect+topLeft(A6)    ; dstRect is right-shifted one.
  95.         MOVE.L    D1,dstRect+botRight(A6)
  96.         MOVE.L    A3,-(SP)        ; srcBits = srcMap.
  97.         PEA    rgnMap(A6)        ; dstBits = rgnMap.
  98.         PEA    bounds(A3)        ; srcRect = srcMap.bounds.
  99.         PEA    dstRect(A6)        ; dstRect.
  100.         MOVE.W    D4,-(SP)        ; srcCopy mode.
  101.         MOVE.L    D4,-(SP)        ; no maskRgn.
  102.         _CopyBits
  103. ;
  104. ; XOR srcMap with right-shifted copy rgnMap and store in rgnMap.
  105. ;
  106.         MOVE.L    A3,-(SP)        ; srcBits = srcMap.
  107.         PEA    rgnMap(A6)        ; dstBits = rgnMap.
  108.         PEA    bounds(A3)        ; srcRect = srcMap.bounds.
  109.         PEA    bounds(A3)        ; dstRect = srcMap.bounds.
  110.         MOVE.W    #srcXor,-(SP)        ; srcXor mode.
  111.         MOVE.L    D4,-(SP)        ; no maskRgn.
  112.         _CopyBits
  113. ;
  114. ; XOR rgnMap with down-shifted copy of rgnMap.
  115. ;
  116.         MOVE.L    rgnMap+bounds+topLeft(A6),srcRect+topLeft(A6)
  117.         MOVE.L    rgnMap+bounds+botRight(A6),srcRect+botRight(A6)
  118.         MOVE.L    srcRect+topLeft(A6),dstRect+topLeft(A6)
  119.         MOVE.L    srcRect+botRight(A6),dstRect+botRight(A6)
  120.         SUBQ.W    #1,srcRect+bottom(A6)
  121.         ADDQ.W    #1,dstRect+top(A6)
  122.         PEA    rgnMap(A6)        ; srcBits = rgnMap.
  123.         PEA    rgnMap(A6)        ; dstBits = rgnMap.
  124.         PEA    srcRect(A6)        ; srcRect is top overlap.
  125.         PEA    dstRect(A6)        ; dstRect is bottom overlap.
  126.         MOVE.W    #srcXor,-(SP)        ; srcCopy mode.
  127.         MOVE.L    D4,-(SP)        ; no maskRgn.
  128.         _CopyBits
  129. ;
  130. ; We've exposed the inversion points of the picture.  Time to
  131. ; count the number of rows and black pixels in the rgnMap to determine
  132. ; the size of the RgnHandle we will soon fill in.
  133. ;
  134.         MOVE.L    rgnMap+baseAddr(A6),A0    ; start at topLeft of bitmap.
  135.         LSR.W    #1,D7            ; rowWords = rowBytes/2.
  136.         SUBQ.W    #1,D7            ; loop rowWords times.
  137.         MOVE.W    rgnMap+bounds+top(A6),D1 ; current Y coordinate.
  138.         MOVE.W    rgnMap+bounds+bottom(A6),A1 ; Y coord. for end test.
  139.         MOVEQ    #0,D5            ; row count = 0.
  140. Count
  141.         MOVE.W    D7,D6            ; x loop on rowWords.
  142.         MOVEQ    #0,D3            ; clear line flag.
  143. @0
  144.         MOVE.W    (A0)+,D0        ; load next rgnMap word.
  145.         BEQ.S    @2            ; skip blank words.
  146.         TST.B    D3            ; line flag already set?
  147.         BNE.S    @1            ; yes --> skip.
  148.         ST    D3            ; no --> set line flag.
  149.         ADDQ.W    #1,D5            ; row count++.
  150. @1
  151.         ADDQ.W    #1,D4            ; add number of bits
  152.         MOVE.W    D0,D2            ; in rgnMap word to
  153.         SUBQ.W    #1,D2            ; total bit count.
  154.         AND.W    D2,D0
  155.         BNE.S    @1
  156. @2
  157.         DBRA    D6,@0            ; loop if more words to read.
  158.         ADDQ.W    #1,D1            ; y++.
  159.         CMP.W    D1,A1            ; y <= bottom?
  160.         BGT.S    Count            ; yes --> loop.
  161. ;
  162. ; Determine size of new RgnHandle.
  163. ;
  164.         TST.W    D5            ; was the rgnMap empty?
  165.         BNE.S    BuildRgn        ; no --> skip.
  166.         SUBQ.W    #4,SP            ; yes --> get new empty region.
  167.         _NewRgn
  168.         MOVE.L    (SP)+,dstRgn(A6)    ; stuff result.
  169.         BRA    Done            ; exit.
  170. BuildRgn
  171. ;
  172. ; Calculate number of bytes to allocate for output region handle.
  173. ;
  174.         MOVEQ    #12,D0            ; (12 for header & end-of-rgn mark.)
  175.         ADD.W    D5,D5            ; (4*number of lines in map for
  176.         ADD.W    D5,D5            ; each Y coordinate and
  177.         ADD.W    D5,D0            ; end mark.)
  178.         ADD.W    D4,D4            ; (2*number of inversion
  179.         ADD.W    D4,D0            ; points in the entire map.)
  180.         MOVE.W    D0,D4            ; remember the region size.
  181.         _NewHandle ,clear        ; allocate a cleared RgnHandle.
  182.         MOVE.L    A0,dstRgn(A6)        ; store handle in result.
  183. ;
  184. ; Translate rgnMap (containing inversion points) into Quickdraw Region
  185. ; format. We do not need to lock the block because we will be making no
  186. ; trap calls (which might rearrange the heap). DstRect will be used to
  187. ; help us find the smallest enclosing rectangle for the region.
  188. ;
  189.         MOVE.L    (A0),A0            ; point to rgn data.
  190.         MOVE.W    D4,rgnSize(A0)        ; store region size.
  191.         MOVE.L    A0,A2            ; save ptr for the end.
  192.         LEA    rgnData(A0),A0        ; offset ptr to rgnData.
  193.         MOVE.L    rgnMap+baseAddr(A6),A1    ; point to topLeft of bitmap.
  194.         MOVE.W    rgnMap+bounds+top(A6),D1 ; y = top.
  195.         MOVE.W    D1,dstRect+bottom(A6)    ; initialize dstRect...
  196.         MOVE.W    rgnMap+bounds+left(A6),dstRect+right(A6)
  197.         MOVE.L    rgnMap+bounds+botRight(A6),dstRect+topLeft(A6)
  198. ;
  199. ; The line flag tells us if the scanline is not completely blank after
  200. ; reading the whole line.  If not blank, then we add an end-of-line mark.
  201. ;
  202. Translate
  203.         MOVE.W    D7,D6            ; load word count.
  204.         MOVEQ    #0,D5            ; clear line flag.
  205.         MOVE.W    rgnMap+bounds+left(A6),D3 ; x = left edge.
  206. @0
  207.         MOVE.W    (A1)+,D0        ; load srcMap word.
  208.         BNE.S    @NotEmpty        ; only process non-zero words.
  209.         ADD.W    #16,D3            ; skip zero words for speed.
  210.         BRA.S    @4
  211. @NotEmpty
  212.         TST.B    D5            ; is line flag set?
  213.         BNE.S    @1            ; yes --> skip.
  214.         ST    D5            ; no --> set line flag.
  215.         MOVE.W    D1,(A0)+        ; store y coord. in structure.
  216.         CMP.W    dstRect+top(A6),D1    ; now find the topmost
  217.         BGE.S    @MaxBottom        ; row of the region.
  218.         MOVE.W    D1,dstRect+top(A6)    ; top = min(top,y).
  219. @MaxBottom
  220.         CMP.W    dstRect+bottom(A6),D1    ; now find the bottommost
  221.         BLE.S    @1            ; row of the region.
  222.         MOVE.W    D1,dstRect+bottom(A6)    ; bottom = max(bottom,y).
  223. @1
  224.         OR.B    #$10,CCR        ; set the X flag.
  225.         ADDX.W    D0,D0            ; shift in end-bit-marker.
  226. @2
  227.         BCC.S    @3            ; branch if MSB clear.
  228.         MOVE.W    D3,(A0)+        ; store x coord. in structure.
  229.         CMP.W    dstRect+left(A6),D3    ; now find the leftmost
  230.         BGE.S    @MaxRight        ; edge of the region.
  231.         MOVE.W    D3,dstRect+left(A6)    ; left = min(left,x).
  232. @MaxRight
  233.         CMP.W    dstRect+right(A6),D3    ; now find the rightmost
  234.         BLE.S    @3            ; edge of the region.
  235.         MOVE.W    D3,dstRect+right(A6)    ; right = max(right,x).
  236. @3
  237.         ADDQ.W    #1,D3            ; increment the x coordinate.
  238.         ADD.W    D0,D0            ; shift msb into carry.
  239.         BNE.S    @2            ; repeat if more one-bits.
  240. @4
  241.         DBRA    D6,@0            ; loop on rowWords-1.
  242.         TST.B    D5            ; empty line?
  243.         BEQ.S    @5            ; yes -->
  244.         MOVE.W    #ENDMARK,(A0)+        ; no, store end-of-line mark.
  245. @5
  246.         ADDQ.W    #1,D1            ; increment the y coordinate.
  247.         CMP.W    rgnMap+bounds+bottom(A6),D1 ; loop if y <= bottom of rgnMap.
  248.         BLT.S    Translate
  249. ;
  250. ; We are finished entering information into the rgnData field.
  251. ; Mark the end of the region and fill in the rgnBBox field.
  252. ;
  253.         MOVE.W    #ENDMARK,(A0)        ; store end-of-region mark.
  254.         MOVE.L    dstRect+topLeft(A6),rgnBBox+topLeft(A2)
  255.         MOVE.L    dstRect+botRight(A6),rgnBBox+botRight(A2)
  256. Done            
  257.         MOVE.L    rgnMap+baseAddr(A6),A0    ; deallocate temporary bitmap.
  258.         _DisposPtr
  259.         
  260.         MOVEM.L    (SP)+,A1-A3/D0-D7    ; restore working registers.
  261.         UNLK    A6            ; unlink the stack frame.
  262.         MOVE.L    (SP)+,A0        ; load return address.
  263.         ADDQ.W    #4,SP            ; pop parameter.
  264.         JMP    (A0)            ; return.
  265.         ENDWITH
  266.         ENDPROC
  267.         END
  268.